package org.springframework.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * 模拟环绕Advice链的递归执行过程
 *         1. proceed() 方法调用链中下一个环绕通知
 *         2. 每个环绕通知内部继续调用 proceed()
 *         3. 调用到没有更多通知了, 就调用目标方法
 */
public class A18_1 {

    static class Target{
        public void foo(){
            System.out.println("foo....");
        }
    }

    static class MyAdvice1 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("myAdvice1 before...");
            Object result = invocation.proceed();
            System.out.println("myAdvice1 after...");
            return result;
        }
    }

    static class MyAdvice2 implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("myAdvice2 before...");
            Object result = invocation.proceed();
            System.out.println("myAdvice2 after...");
            return result;
        }
    }

    static class MyMethodInvocation implements MethodInvocation{

        private Object target;
        private Method method;
        private Object[] argument;
        private List<MethodInterceptor>  methodInterceptors;
        int count;

        public MyMethodInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> interceptors){
            this.target = target;
            this.method = method;
            this.argument = args;
            this.methodInterceptors = interceptors;
            count = 0;
        }

        @Override
        public Method getMethod() {
            return method;
        }

        @Override
        public Object[] getArguments() {
            return argument;
        }

        /**
         * 整个递归逻辑还是值得思考积累的。买本设计模式，研究一下责任链模式
         * todo 思考这个在动态代理中怎么用
         */
        @Override
        public Object proceed() throws Throwable {
            if (count >= methodInterceptors.size()) {
                return method.invoke(target, argument);
            }
            MethodInterceptor interceptor = methodInterceptors.get(count++);
            return interceptor.invoke(this);
        }

        @Override
        public Object getThis() {
            return target;
        }

        @Override
        public AccessibleObject getStaticPart() {
            return method;
        }
    }

    public static void main(String[] args) throws Throwable {
        Target target = new Target();
        Method method = Target.class.getMethod("foo");
        List<MethodInterceptor> list = new LinkedList<>();
        Collections.addAll(list, new MyAdvice1(), new MyAdvice2());
        MyMethodInvocation methodInvocation = new MyMethodInvocation(target, method, new Object[0], list);
        methodInvocation.proceed();
    }
}
